#!/bin/sh
# rpmwand for building rpm package.
#
# Copyright(c) 2010, Hojin Choi <hojin.choi@gmail.com>
# All rights reserved.
#
# See project url: http://code.google.com/p/rpmwand/
# You can freely redistribute this program under the new bsd license.
# License copy: http://www.opensource.org/licenses/bsd-license.php
#

_VERSION=0.9.3
_RPMDIR="$(pwd)/RPMS"
_SHELL=bash

check_env() {
	rpmbuild --help >/dev/null 2>&1 || {
		echo "You need rpmbuild, install 'rpm-build' package"
		exit 1
	}
}

init_spec() {
	NAME="$1"
	SPEC_INPUT="$NAME.spec.in"
	if test -f "$SPEC_INPUT"; then
		echo "There already exists spec file($SPEC_INPUT). Remove it first!"
		exit 1
	fi
	echo "#Generated by rpmwand v. $_VERSION $(date)" > "$SPEC_INPUT"
	cat >> "$SPEC_INPUT" <<"END_OF_SPEC_INPUT"
%define _builddir @FAKEROOT@/
%define _topdir /
%define _buildrootdir @FAKEROOT@
%define _rpmdir @RPMDIR@
%define _tmppath @FAKEROOT@/tmp
%define _sourcedir @FAKEROOT@/..
%define debug_package %{nil}

Summary: TODO. PLEASE EDIT ME!
Vendor: TODO. PLEASE EDIT ME!
Packager: TODO. PLEASE EDIT ME!
License: TODO. PLEASE EDIT ME!
Group: TODO. PLEASE EDIT ME!
URL: http://TODO.example.com/

Name: @NAME@
Version: @VERSION@
Release: @RELEASE@
Source: %name-%version.tar.gz
BuildRoot: @FAKEROOT@/
AutoReqProv: no
#Requires:

%description
TODO. PLEASE EDIT ME!

##########################################################################################
# BUILD-TIME SCRIPTS
##########################################################################################
%prep
true "=================================================================================="
true "BEG Build preprocess"
true "END Build preprocess"

%setup -q
true "=================================================================================="
true "BEG Setup"
true "END Setup"

%build
true "=================================================================================="
true "BEG Build"
echo "BUILDROOT: %{buildroot}"
echo "BUILDROOTDIR: %{_buildrootdir}"
echo "PACKAGE-NAME: %{name}"
echo "PACKAGE-VERSION: %{version}"
echo "PACKAGE-RELEASE: %{release}"
true "END Build"

%install
true "=================================================================================="
true "BEG Installation"
#Creating fake Makefile
%{__cat} > "%{_buildrootdir}/%{name}-%{version}/Makefile" <<EOT
install:
	@echo ""
	@echo "I am FAKE Makefile install target. Do you see me?"
	@echo ""
EOT


true "END Installation"

%makeinstall
true "=================================================================================="
true "BEG make install"
true BUILDROOTDIR:%{_buildrootdir}
%{__rm} -rf "%{_buildrootdir}/%{name}-%{version}/Makefile"
#Installing all contents to fake root
if test ! "%{buildroot}" = "%{_buildrootdir}"; then
	%{__rm} -rf "%{buildroot}"/*
	%{__mkdir} -p "%{buildroot}"
fi
mv "%{_buildrootdir}/%{name}-%{version}"/* "%{buildroot}"

true "END make install"

%clean
true "=================================================================================="

%files -f "@FAKEROOT@/../%{name}-files.txt"

##########################################################################################
# INSTALL/UNINSTALL-TIME SCRIPTS
##########################################################################################
%pretrans
true BEG Pre-transaction script
# Usually umask here
umask 007

%pre
true BEG Pre-installation script
if test "$1" = "1"; then # Install
	#Place your script pre-install script
	#echo "Pre-install script version:" %{version}>> /tmp/%{name}.log
	:
else # Update ($1 = "2")
	#Place your script pre-update script
	#echo "Pre-update script of new version:" %{version}>> /tmp/%{name}.log
	:
fi

true END Pre-installation script

%post
true BEG Post-installation script
if test "$1" = "1"; then # Install
	#Place your script post-install script
	#echo "Post-install script version:" %{version}>> /tmp/%{name}.log
	:
else # Update ($1 = "2")
	#Place your script post-update script
	#echo "Post-update script of new version:" %{version}>> /tmp/%{name}.log
	:
fi


true END Post-installation script

%preun
true BEG Pre-uninstall script
if test "$1" = "0"; then # Uninstall
	#Place your script pre-uninstall script
	#echo "Pre-uninstall script version:" %{version}>> /tmp/%{name}.log
	:
else # Uninstall by new version ($1 = "1")
	#Place your script pre-update script
	#echo "Pre-update script of old version:" %{version}>> /tmp/%{name}.log
	:
fi

true END Pre-uninstall script

%postun
true BEG Post-uninstall script
#Place temporary file cleaner here.
#Place user deletion script here.
if test "$1" = "0"; then # Uninstall
	#Place your script post-uninstall script
	echo "Post-uninstall script version:" %{version}>> /tmp/%{name}.log
	:
else # Uninstall by new version ($1 = "1")
	#Place your script post-update script
	echo "Post-update script of old version:" %{version}>> /tmp/%{name}.log
	:
fi

true END Post-uninstall script

%changelog

END_OF_SPEC_INPUT
	echo "* Created spec input file: $SPEC_INPUT"
	echo "  Please edit $SPEC_INPUT"
	echo "  Fix TODO values"
	echo ""
}

init_skel() {
	NAME="$1"
	SKEL_DIR="$NAME-skel"
	if test -d "$SKEL_DIR"; then
		echo "Skeleton directory($SKEL_DIR) exists, Remove it first!"
		exit 1
	fi
	mkdir -p "$SKEL_DIR/etc"
	mkdir -p "$SKEL_DIR/usr/local/bin"
	mkdir -p "$SKEL_DIR/usr/local/lib"
	mkdir -p "$SKEL_DIR/usr/share/man/man1"
	echo "Sample etc" > "$SKEL_DIR/etc/sample.conf"
	cat > "$SKEL_DIR/usr/local/bin/sample-bin" <<"END_OF_SAMPLE"
#!/bin/sh
echo "Hello, world"
END_OF_SAMPLE
	chmod +x "$SKEL_DIR/usr/local/bin/sample-bin"
	echo "* Created skeleton directory: '$SKEL_DIR'"
	echo ""
}

extract_files() {
	NAME="$1"
	SKEL_DIR="$NAME-skel"
	FILES_FILE="$NAME-files.txt"
	if test ! -d "$SKEL_DIR"; then
		echo "There is no $SKEL_DIR, Init first"
		exit 1
	fi
	( cd "$SKEL_DIR" && find . | {
		echo "#File list of $NAME"
		echo "#See details of directives at http://www.rpm.org/max-rpm/s1-rpm-inside-files-list-directives.html"
		echo ""
		while read line
		do
			if test "$line" = "."; then
				continue
			fi
			PERM=`stat -c %a $line`
			if test -d $line; then
				echo $line | grep -q "^./\(home\|usr\|etc\|opt\|usr/local\|etc/init.d\)$"
				if test $? -eq 1; then
					echo "%dir____$line"
				fi
			else
				if echo $line | grep -q "\.\(conf\|cfg\|ini\|cf\)$"; then
					echo "%config %attr($PERM,-,-)____$line"
				else
					echo "%attr($PERM,-,-)____$line"
				fi
			fi
		done | sed -e 's@____.@ @'
	} ) > "$FILES_FILE"
	echo "* Created file list: $FILES_FILE"
	echo "  Please edit $FILES_FILE"
	echo ""
}

build() {
	if test -z "$1"; then
		help
		exit 1
	fi

	NAME="$1"
	_VERSION="1.0.0"
	RELEASE="1"
	ARCH="noarch"
	if test -n "$2"; then
		_VERSION="$2"
	fi
	if test -n "$3"; then
		RELEASE="$3"
	fi
	if test -n "$4"; then
		ARCH="$4"
	fi
	SPECSKEL="$NAME.spec.in"

	PKGFULLNAME="$NAME-$_VERSION"
	PKGFULLPATH="$(pwd)/$PKGFULLNAME"
	FAKEROOT="$(pwd)/faked-root.$$"

	echo " * Package name : $NAME"
	echo " * Version      : $_VERSION"
	echo " * Release      : $RELEASE"
	echo ""

	rm -rf "$PKGFULLNAME/"
	rm -rf faked-root.*
	mkdir -p "$FAKEROOT" || {
		echo "Can't make temporary root directory for building rpm"
		exit 1
	}
	mkdir "$_RPMDIR" 2>/dev/null

	echo "--------------------------------------------------------------------------"
	echo "* Making tarball($PKGFULLNAME.tar.gz) for rpm build..."
	echo "* Tarball($PKGFULLNAME.tar.gz) is assumed containing '$PKGFULLNAME' directory as the first child item"
	echo "* Cloning '$NAME-skel' directory to '$PKGFULLNAME'"
	cp -rp "$NAME-skel/" "$PKGFULLNAME/"
	echo "* Check if there is custom packaging script ($NAME-setup.sh)"
	if test -f "$NAME-setup.sh"; then
		"$_SHELL" "$NAME-setup.sh" "$PKGFULLPATH"
	else
		echo "  skip running: $_SHELL $NAME-setup.sh $PKGFULLPATH"
	fi
	echo "* Tarring '$PKGFULLNAME.tar.gz' from '$PKGFULLNAME'"
	tar czf "$PKGFULLNAME.tar.gz" "$PKGFULLNAME"

	echo "--------------------------------------------------------------------------"
	echo "* Now, building rpm...."
	cat "$SPECSKEL" | \
		sed \
			-e "s;@VERSION@;$_VERSION;g" \
			-e "s;@RELEASE@;$RELEASE;g" \
			-e "s;@NAME@;$NAME;g" \
			-e "s;@FAKEROOT@;$FAKEROOT;g" \
			-e "s;@RPMDIR@;$_RPMDIR;g" \
		> "$NAME.spec"

	rm -rf faked-root.*
	LANG=C rpmbuild -bb "$NAME.spec" --target $ARCH || exit 1

	echo "--------------------------------------------------------------------------"
	echo " * RPM build done..."

	echo ""
	echo " * Check.."
	find "$_RPMDIR" -type f
	echo ""
}

subst() {
	export | grep "^export" | awk '{print $2}' | awk -F= '{print $1}' > /tmp/a.export
	SRC="$1"
	TARGET="$2"
	shift 2
	rm -f /tmp/rpmwand.$$.awk
	for token in $@
	do
		echo "s;@$token@;$(eval echo \$$token);g" >> /tmp/rpmwand.$$.awk
	done
	echo "Building $TARGET from $SRC"
	sed -f /tmp/rpmwand.$$.awk $SRC > $TARGET.tmp
	if cmp -s "$TARGET" "$TARGET.tmp"; then
		:
	else
		mv $TARGET.tmp $TARGET
	fi
	rm -f /tmp/rpmwand.$$.awk
}

help() {
	cat <<ENDOFCAT
Usage: rpmwand <command> <name> [<args>...]

Simple RPM Builder, version $_VERSION by Hojin Choi <hojin.choi@gmail.com>

Main Command:
    init <name>
        : Create rpm spec template and skeleton directory filled with samples

    build <name> [<version> [<release> [<arch>]]]
        : Build rpm with options

Sub Command:
    files <name>
        : Extract file list from skeleton directory

    initspec <name>
        : Make spec file template only.

    subst <file> <new file> <environment-var> [<environment-var>...]
        : read <file> and convert all words like @environment-var@ patterns to the value of
          environment, and store the result to <new file>

    help
        : This help.
ENDOFCAT
}

check_env || exit 1

case "$1" in 
init)
	shift
	if test $# -ne 1; then
		help
		exit
	fi
	init_skel "$@"
	extract_files "$@"
	init_spec "$@"
	;;
initspec)
	shift
	if test $# -ne 1; then
		help
		exit
	fi
	init_spec "$@"
	;;
build)
	shift
	if test $# -lt 1; then
		help
		exit
	fi
	build "$@"
	;;
files)
	shift
	if test $# -lt 1; then
		help
		exit
	fi
	extract_files "$@"
	;;
subst)
	shift
	if test $# -le 2; then
		help
		exit
	fi
	subst $@
	;;
*|help|--help|-h)
	help
	;;
esac
exit 0
